package co.yixiang.modules.monitoring.serviceimpl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import co.yixiang.common.exception.BadRequestException;
import co.yixiang.common.exception.ServiceException;
import co.yixiang.common.service.impl.BaseServiceImpl;
import co.yixiang.common.utils.QueryHelpPlus;
import co.yixiang.dozer.service.IGenerator;
import co.yixiang.modules.adopt.entity.domain.YxAdoptProduct;
import co.yixiang.modules.monitoring.entity.domain.YxMonitoring;
import co.yixiang.modules.monitoring.entity.dto.ChannelDto;
import co.yixiang.modules.monitoring.entity.dto.YxMonitoringDto;
import co.yixiang.modules.monitoring.entity.enums.DeviceTypeEnum;
import co.yixiang.modules.monitoring.entity.query.YxMonitoringQueryCriteria;
import co.yixiang.modules.monitoring.entity.vo.YxMonitoringSmallVo;
import co.yixiang.modules.monitoring.fluorite.entity.FluoriteQueryForm;
import co.yixiang.modules.monitoring.fluorite.entity.dto.CameraDto;
import co.yixiang.modules.monitoring.fluorite.service.FluoriteService;
import co.yixiang.modules.monitoring.mapper.MonitoringMapper;
import co.yixiang.modules.monitoring.service.YxMonitoringService;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
@Transactional(propagation = Propagation.SUPPORTS,readOnly = true,rollbackFor = Exception.class)
public class YxMonitoringServiceImpl extends BaseServiceImpl<MonitoringMapper, YxMonitoring> implements YxMonitoringService {
    @Autowired
    private IGenerator generator;
    @Autowired
    private FluoriteService fluoriteService;

    @Override
    public Map<String, Object> queryAllByCateId(YxMonitoringQueryCriteria criteria, Pageable pageable) {
        getPage(pageable);
        List<YxMonitoring> monitoringList = baseMapper.selectByMyWrapper(criteria.getLng(),criteria.getLat(),QueryHelpPlus.getPredicate(YxAdoptProduct.class, criteria));
        List<YxMonitoring> monitoringListT = new ArrayList<>();
        for (YxMonitoring monitor: monitoringList) {
            if (monitor.getType().equals(DeviceTypeEnum.NVR.name())) {
                JSONArray objects = JSONUtil.parseArray(monitor.getChannelData());
                objects.forEach(channel -> {
                    final ChannelDto channelDto = JSONUtil.toBean(JSONUtil.toJsonStr(channel), ChannelDto.class);
                    final YxMonitoring yxMonitoring = BeanUtil.copyProperties(monitor, YxMonitoring.class);
                    yxMonitoring.setName(channelDto.getChannelName());
                    yxMonitoring.setChannel(channelDto.getChannelNo());
                    monitoringListT.add(yxMonitoring);
                });
                continue;
            }
            monitor.setChannel("1");
            monitoringListT.add(monitor);
        }
        PageInfo<YxMonitoring> page = new PageInfo<>(monitoringListT);
        Map<String, Object> map = new LinkedHashMap<>(2);
        map.put("content",generator.convert(page.getList(), YxMonitoringSmallVo.class));
        map.put("totalElements", page.getTotal());
        return map;
    }

    @Override
    public YxMonitoringSmallVo queryMonitoringDetail(Long id,String channel) {
        // 进入监控
        final YxMonitoring monitor = this.getById(id);
        if (ObjectUtil.isEmpty(monitor)) {
            throw new ServiceException("ID为:" + id + "监控不存在");
        }
        if (monitor.getType().equals(DeviceTypeEnum.NVR.name())) {
            JSONArray objects = JSONUtil.parseArray(monitor.getChannelData());
            objects.forEach(chan -> {
                final ChannelDto channelDto = JSONUtil.toBean(JSONUtil.toJsonStr(chan), ChannelDto.class);
                if (channelDto.getChannelNo().equals(channel)) {
                    monitor.setName(channelDto.getChannelName());
                    monitor.setChannel(channelDto.getChannelNo());
                }
            });
        }
        // 修改浏览次数
        this.update(new LambdaUpdateWrapper<YxMonitoring>().set(YxMonitoring::getVisit, monitor.getVisit() + 1).eq(YxMonitoring::getId, id));
        final YxMonitoringSmallVo yxMonitoringSmallVo = BeanUtil.copyProperties(monitor, YxMonitoringSmallVo.class);
        return yxMonitoringSmallVo;
    }

    @Override
    public Map<String, Object> queryAll(YxMonitoringQueryCriteria criteria, Pageable pageable) {
        getPage(pageable);
        PageInfo<YxMonitoring> page = new PageInfo<>(queryAll(criteria));
        Socket socket = new Socket();
        page.getList().forEach(monitor -> {
           String url =  "rtsp://"+monitor.getUsername()+":"+monitor.getPasswd()+"@"+monitor+":"+monitor.getPort()+"/Streaming/Channels/"+monitor.getChannel();
           if (monitor.getMulticast()) {
               url += "?transportmode=multicast";
           }
           monitor.setUrl(url);
            // 建立TCP Scoket连接，超时时间1s，如果成功继续执行，否则return
            // 设备状态进行判断
            try {
                socket.connect(new InetSocketAddress(monitor.getHost(), monitor.getPort()), 1000);
            } catch (IOException e) {
                monitor.setStatus(1);
            }
        });
        Map<String, Object> map = new LinkedHashMap<>(2);
        map.put("content", generator.convert(page.getList(), YxMonitoringDto.class));
        map.put("totalElements", page.getTotal());
        return map;
    }

    @Override
    public List<YxMonitoring> queryAll(YxMonitoringQueryCriteria criteria) {
        return baseMapper.selectList(QueryHelpPlus.getPredicate(YxMonitoring.class, criteria));
    }

    @Override
    public YxMonitoring saveMonitoring(YxMonitoring monitoring, Boolean flag) {

        if (flag) {
            // 调用萤石云，增加设备接口
            FluoriteQueryForm form = new FluoriteQueryForm();
            form.copy(monitoring);
            // 添加设备
            fluoriteService.deviceAdd(form);
            // 获取设备的所有通道数
            final List<CameraDto> cameras = fluoriteService.deviceCameraList(form);
            StringBuilder source = new StringBuilder();
            cameras.forEach(v -> {
                source.append(v.getDeviceSerial());
                source.append(":");
                source.append(v.getChannelNo());
            });
            form.setSource(source.toString());
            // 开通直播功能
            //fluoriteService.videoOpen(form);
        }
        // 设备类型为'NVR'是处理通道数据
        if ("NVR".equals(monitoring.getType())){
            monitoring.setChannelData(JSONUtil.toJsonStr(monitoring.getChannelList()));
        }
        // 持久化到数据库
        this.save(monitoring);
        // 保存设备的POINT信息
        this.updatePosition(monitoring);
        return monitoring;
    }

    @Override
    public Boolean removeMonitoring(Integer id) {
        // 调用萤石云，删除设备接口
        final YxMonitoring monitoring = this.getById(id);
        FluoriteQueryForm form = new FluoriteQueryForm();
        form.copy(monitoring);
        fluoriteService.deviceDelete(form);
        this.removeById(id);
        return null;
    }

    @Override
    public YxMonitoring updateMonitoring(YxMonitoring monitoring) {
        final YxMonitoring byId = this.getById(monitoring.getId());
        if(ObjectUtil.isEmpty(byId)) {
            throw new BadRequestException(500,"找不多监控要修改的监控设备");
        }
        // 判断一下，监控序列号是否变化,有变化调用萤石云接口，先删除设备，再添加
        if (ObjectUtil.isNotEmpty(byId.getDeviceSerial()) && byId.getDeviceSerial().equals(monitoring.getDeviceSerial())) {
            FluoriteQueryForm form = new FluoriteQueryForm();
            form.copy(monitoring);
            // 删除添加
            fluoriteService.deviceDelete(form);
            // 添加
            fluoriteService.deviceAdd(form);
            // 获取设备的所有通道数
            final List<CameraDto> cameras = fluoriteService.deviceCameraList(form);
            StringBuilder source = new StringBuilder();
            cameras.forEach(v -> {
                source.append(v.getDeviceSerial());
                source.append(":");
                source.append(v.getChannelNo());
            });
            form.setSource(source.toString());
            // 开通直播功能
            //fluoriteService.videoOpen(form);
        }
        // 设备类型为'NVR'是处理通道数据
        if ("NVR".equals(monitoring.getType())){
            monitoring.setChannelData(JSONUtil.toJsonStr(monitoring.getChannelList()));
        }
        this.saveOrUpdate(monitoring);
        this.updatePosition(monitoring);
        return monitoring;
    }

    public void updatePosition(YxMonitoring monitoring) {
        if (ObjectUtil.isNotEmpty(monitoring.getId())){
            String ss1 = "POINT(" + monitoring.getPositionStr().replace(",", " ") + ")";
            this.baseMapper.updatePosition(ss1, monitoring.getId().toString());
        }
    }
}
